/* 包含头文件-----------------------------------------------------------------*/
#include "pwm_dma.h"

/* 私有宏定义-----------------------------------------------------------------*/
/* 定时器2的PWM DMA使能  1:通道1-PA0  2:通道2-PA1  3:通道3-PA2  4:通道4-PA3 */
#define TIM2_PWM_DMA_EN                 (1)

#if (1 == TIM2_PWM_DMA_EN)
#define TIM_DMA_CH                      (DMA1_Channel5)
#define TIM_CCR_ADDR                    (TIM2->CCR1)
#define DMA_IRQ_FUN                     (DMA1_Channel5_IRQHandler)
#define DMA_IRQ_FLAG                    (DMA1_IT_TC5)
#elif (2 == TIM2_PWM_DMA_EN)
#define TIM_DMA_CH                      (DMA1_Channel7)
#define TIM_CCR_ADDR                    (TIM2->CCR2)
#define DMA_IRQ_FUN                     (DMA1_Channel7_IRQHandler)
#define DMA_IRQ_FLAG                    (DMA1_IT_TC7)
#elif (3 == TIM2_PWM_DMA_EN)
#define TIM_DMA_CH                      (DMA1_Channel1)
#define TIM_CCR_ADDR                    (TIM2->CCR3)
#define DMA_IRQ_FUN                     (DMA1_Channel1_IRQHandler)
#define DMA_IRQ_FLAG                    (DMA1_IT_TC1)
#elif (4 == TIM2_PWM_DMA_EN)
#define TIM_DMA_CH                      (DMA1_Channel7)
#define TIM_CCR_ADDR                    (TIM2->CCR4)
#define DMA_IRQ_FUN                     (DMA1_Channel7_IRQHandler)
#define DMA_IRQ_FLAG                    (DMA1_IT_TC7)
#endif

/* 私有类型定义---------------------------------------------------------------*/

/* 私有变量-------------------------------------------------------------------*/

/* 全局变量-------------------------------------------------------------------*/

/* 私有函数原型---------------------------------------------------------------*/

/**
  * @brief  pwm初始化
  * @param  arr : 重装值
  * @param  psc : 预分频数
  * @retval None
  */
static void pwm_config(uint16_t arr, uint16_t psc)
{
    GPIO_InitTypeDef GPIO_InitStructure;
    TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
    TIM_OCInitTypeDef  TIM_OCInitStructure;
    
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO, ENABLE); /* 使能GPIO外设时钟使能 */
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); /* 开启定时器时钟 */
    
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
#if (1 == TIM2_PWM_DMA_EN)
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
#elif (2 == TIM2_PWM_DMA_EN)
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;
#elif (3 == TIM2_PWM_DMA_EN)
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
#elif (4 == TIM2_PWM_DMA_EN)
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;
#endif
    GPIO_Init(GPIOA, &GPIO_InitStructure);
    
    TIM_DeInit(TIM2);
    
    TIM_TimeBaseStructure.TIM_Period = arr - 1; /* 自动重装载值 */
    TIM_TimeBaseStructure.TIM_Prescaler = psc - 1; /* 时钟预分频数 */
    TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; /* 时钟分频系数 1分频 */
    TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; /* 计数模式 向上计数 */
    TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure); /* 初始化定时器 */

    TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; /* PWM模式1 */
    TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; /* 输出使能 */
    TIM_OCInitStructure.TIM_Pulse = 0; /* 比较值 */
    TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; /* 输出极性高 */
    TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Reset; /* 空闲状态为低 */
    TIM_OC1Init(TIM2, &TIM_OCInitStructure); /* 初始化比较输出 */
    TIM_OC1PreloadConfig(TIM2, TIM_OCPreload_Enable); /* OC预装载使能 */
    
    TIM_Cmd(TIM2, DISABLE); /* 开启定时器 */
}

/**
  * @brief  DMA初始化
  * @param  memory : 内存基地址
  * @retval None
  */
static void dma_config(void *memory)
{
    DMA_InitTypeDef DMA_InitStructure;
    
    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE); /* 打开DMA时钟 */
    
    DMA_DeInit(TIM_DMA_CH);
    DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&TIM_CCR_ADDR; /* 外设基地址 */
    DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)memory; /* 内存基地址 */
    DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST; /* 数据方向 外设作为目标源 */
    DMA_InitStructure.DMA_BufferSize = 0; /* 数据数量 */
    DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; /* 外设基地址不递增 */
    DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; /* 内存基地址递增 */
    DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord; /* 外设数据大小为字节 2byte */
    DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord; /* 内存数据大小为字节 2byte */
    DMA_InitStructure.DMA_Mode = DMA_Mode_Normal; /* 传输模式 单次传输 */
    DMA_InitStructure.DMA_Priority = DMA_Priority_High; /* DMA优先级 高 */
    DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; /* 内存到内存禁用 */
    DMA_Init(TIM_DMA_CH, &DMA_InitStructure); /* 初始化DMA */
    
    DMA_ITConfig(TIM_DMA_CH, DMA_IT_TC, ENABLE); /* 开启传输完成中断 */
    DMA_Cmd(TIM_DMA_CH, DISABLE); /* 开启DMA */
    
#if (1 == TIM2_PWM_DMA_EN)
    TIM_DMACmd(TIM2, TIM_DMA_CC1, ENABLE); /* 开启对应通道DMA */
#elif (2 == TIM2_PWM_DMA_EN)
    TIM_DMACmd(TIM2, TIM_DMA_CC2, ENABLE); /* 开启对应通道DMA */
#elif (3 == TIM2_PWM_DMA_EN)
    TIM_DMACmd(TIM2, TIM_DMA_CC3, ENABLE); /* 开启对应通道DMA */
#elif (4 == TIM2_PWM_DMA_EN)
    TIM_DMACmd(TIM2, TIM_DMA_CC4, ENABLE); /* 开启对应通道DMA */
#endif
}

/**
  * @brief  DMA中断函数
  * @param  None
  * @retval None
  */
void DMA_IRQ_FUN(void)
{
    if(DMA_GetITStatus(DMA_IRQ_FLAG) != RESET)
    {
        pwm_dma_stop();
        
        DMA_ClearITPendingBit(DMA_IRQ_FLAG);
    }
}

/**
  * @brief  PWM DMA初始化
  * @param  arr    : 定时器重装值
  * @param  psc    : 定时器预分频数
  * @param  memory : DMA内存基地址
  * @retval None
  */
void pwm_dma_config(uint16_t arr, uint16_t psc, void *memory)
{
    pwm_config(arr, psc);
    dma_config(memory);
}

/**
  * @brief  PWM DMA传输启动
  * @param  size : 传输数量
  * @retval None
  */
void pwm_dma_start(uint16_t size)
{
    DMA_SetCurrDataCounter(TIM_DMA_CH, size);
    DMA_Cmd(TIM_DMA_CH, ENABLE);
    TIM_Cmd(TIM2, ENABLE);
}

/**
  * @brief  PWM DMA传输停止
  * @param  None
  * @retval None
  */
void pwm_dma_stop(void)
{
    DMA_Cmd(TIM_DMA_CH, DISABLE);
    TIM_Cmd(TIM2, DISABLE);
}
